<!DOCTYPE HTML>
<html>

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
  <meta http-equiv="X-UA-Compatible" content="IE=Edge,Chrome=1" />
  <title>JS-Piano</title>
  <!-- Library -->
  <script src="./Library/jquery-3.6.0.js"></script>
  <script src="./Library/vue.js"></script>
  <link rel="stylesheet" href="./Library/e-project.css">
  <link rel="stylesheet" href="./Public/index.css">
</head>

<body>
  <div id="app">
    <div class="IDE">
      <!-- 吸顶层 -->
      <div class="fixedTop ep-pd-l-16rp ep-bs-bb ep-t-white">
        项目名称：<input type="text" class="ep-t-333" style="width:100px;" v-model="projectName"> 键宽度：
        <input type="number" class="ep-t-333" style="width:36px;" v-model="KeyWidth" @change="KeyBoardUpdate" /> 格宽度：
        <input type="number" class="ep-t-333" style="width:36px;" v-model="gridWidth" /> 节拍数：
        <input type="number" class="ep-t-333" style="width:36px;" v-model="movement.step" @change="ChartUpdate" /> 小节数：
        <input type="number" class="ep-t-333" style="width:36px;" v-model="movement.long" @change="ChartUpdate" /> BPM：
        <input type="number" class="ep-t-333" style="width:36px;" v-model="movement.speed" /> 默认音量：
        <input type="number" class="ep-t-333" style="width:36px;" v-model="almostVolume" @change="rectify" />
        <button @click="player">播放</button>
        <button @click="saveProject">保存</button> 读取：
        <input id="files" type="file" @change="readProject" />
      </div>
      <!-- 内容包络 -->
      <div class="PianoBlock ep-flex" style="width:max-content;">
        <!-- 吸边钢琴栏 -->
        <div class="fixedLeft piano-area ep-flex ep-flex-d-cr ep-flex-fs">
          <div v-for="(group,gi) in Piano" class="Ver8 ep-flex ep-flex-d-cr ep-flex-jc-c ep-flex-ai-s ep-t-999 ep-f-13rp ep-ps-r" style="width:90px;">
            <!-- 0 2 4 5 7 9 11 -->
            <!-- 1 3 6 8 10 -->
            <div v-for="(kb,ki) in group" class="piano-key" :scale="kb.scale" :class="kb.type == 'B' ? 'blackKey' : 'whiteKey'" :style="kb.type == 'B' ? ('top:' + kb.offset + 'px;' + 'height:' + kb.area + 'px;line-height:' + kb.area + 'px;') : ('height:' + kb.area + 'px;line-height:' + kb.txtOS + 'px;')">{{kb.key}}</div>
          </div>
        </div>
        <!-- IDE-Chart -->
        <!-- <div class="IDE-Chart ep-flex-fs ep-flex">
          <div class="charts ep-flex" v-for="indexC of Number(long)">
            <div class="steps" v-for="indexS of Number(step)">
              <div v-for="(grid,indexG) in Chart" class="grid" :class="(grid.type == 'B' ? 'gridB ' : '') + (grid.groupEnd ? 'gE ' : '') + (grid.isPlay ? 'gridAct ' : '')" :style="{'height' : KeyWidth + 'px', 'width' : gridWidth + 'px'}" @click="doIt(indexC,indexS,grid,Chart)"></div>
            </div>
          </div>
        </div> -->
        <!-- 二改 -->
        <div class="IDE-Chart ep-flex-fs ep-flex">
          <div v-for="(chart,indexC) in Chart" :class="((indexC / Number(movement.step)) % 2 >= 1 ? (timeAct == indexC ? 'timeAct0 ' : 'charts-bg0 ') : (timeAct == indexC ? 'timeAct1 ' : 'charts-bg1 ')) + ((indexC / Number(movement.step)) % 2 == 1 ? 'cutLine' : ((indexC / Number(movement.step)) % 2 == 0 ? 'cutLine' : ''))"
            @click.stop="selTime(indexC)" :key="indexC" class="charts-nd ep-flex ep-flex-d-c ep-f-10rp">{{indexC}}
            <div v-for="(grid,indexG) in chart" :key="indexG" class="grid" :class="(grid.type == 'B' ? 'gridB ' : '') + (grid.groupEnd ? 'gE ' : '')" :style="('height:'+KeyWidth+'px;width:'+gridWidth+'px;') + (grid.isPlay ? 'background:' + grid.actStyle + ';' : '')"
              @click.stop="MIDI(indexC,indexG,chart,$event)" @contextmenu.prevent="setKey(indexC,indexG,chart)">
              <span v-show="showTime">{{indexC}}</span>
              <!-- {{grid.groupId}} -->
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <script src="./Library/layer/layer.js"></script>
  <script src="./Library/FileSaver/FileSaver.min.js"></script>
  <script src="./Public/api.js"></script>
  <script src="./Public/JS-Piano.js"></script>
  <script src="./res/instruments.js"></script>
  <script src="./Music_G/su.js"></script>
  <script>
    var vm = new Vue({
      el: "#app",
      beforeCreate() {
        window.Editor = new Object;
      },
      data: {
        projectName: 'New Project',
        Piano: E_PIANO, // 键盘 
        Chart: [], // MIDI谱表
        E_KEY: [], // 桥
        KeyWidth: '21',
        gridWidth: '40',
        almostVolume: 70,
        movement: { // 合成乐谱
          step: '4',
          long: '4',
          speed: 60,
          volume: 0.7,
          staff: [],
        },
        timeAct: 0, // 播放进度刻度
        playing: false,
        keyCodeDebug: false,
        showTime: false, // 刻度显示
        actStyle: 'rgba(0, 211, 200, 0.8)',
      },
      mounted() {
        // 播放控制 Music
        // window.Music = Su;

        // title 初始化
        if (window.Music == Su) {
          document.title = "溯"
        } else if (window.Music != Su) {
          document.title = "Piano.js"
        }
        this.KeyBoardUpdate();
        this.ChartUpdate();
        // window.pianist(Su,0,3000);
      },
      methods: {
        MIDI(ci, gi, chart, E) {
          if (E.altKey) {
            this.selTime(ci);
            return false;
          }
          // TODO: 实现打谱与播放，需要拆分
          chart[gi].isPlay = !chart[gi].isPlay; // 改变选择态
          chart[gi].actStyle = this.actStyle;
          var groupArr = []; // 创建音元
          chart.forEach(function(item) {
            if (item.isPlay) {
              var arr = [];
              arr.push(item.key);
              arr.push(item.groupId);
              groupArr.push(arr);
              // console.log(arr); // DEBUG
            }
          })
          if (groupArr.length != 0) {
            this.movement.staff[ci] = groupArr;
          } else {
            this.movement.staff[ci] = ['-'];
          }
          // console.log(this.movement.staff);
          // console.log(this.Chart[ci][gi] === this.Chart[ci + 1][gi]); // TODO: 居然全等？！这代表我无论怎么改，都是改的同一个东西，也代表88键是同一个东西循环而来的，并非独立！靠北，见了鬼了...

          this.$forceUpdate();
        },
        setKey(ci, gi, chart) {
          if (chart[gi].isPlay) {
            var msc = this.movement.staff[ci];
            // 在多维数组中寻找指定项，实现定向修改
            msc.forEach(function(item) {
              if (item.indexOf(chart[gi].key) != -1 && item.indexOf(chart[gi].groupId) != -1) {
                layer.prompt({
                  title: '设置音量 0 ~ 100  (当前:' + (item[2] == undefined ? '读取默认音量[' + vm.almostVolume + ']' : item[2] * 100) + ')',
                  formType: 3
                }, function(vol, index) {
                  vol = vol.replace(/\D/g, '');
                  console.log(vol);
                  layer.close(index); // 关闭上一个弹窗
                  // 限制 0 ~ 100
                  if (vol > 100) vol = 100;
                  if (vol < 0) vol = 0;
                  vol = Number((vol / 100).toFixed(2)); // 换算为 0 ~ 1, 保留两位小数
                  if (!isNaN(vol)) { // 判断非NaN, 写入staff MIDI音量控制器
                    item.splice(2, 1, vol);
                    console.log(item);
                  }
                });
              }
            })
          }
        },
        player() {
          window.pianist(this.movement, this.timeAct);
          this.playing = true;
        },
        stopped() {
          window.stop();
          this.playing = false;
        },
        rectify() {
          this.movement.Volume = Number((this.almostVolume / 100).toFixed(2));
        },
        selTime(index) {
          this.timeAct = index;
        },
        KeyBoardUpdate() {
          this.E_KEY = [];
          // TODO: 不要在html中实时计算，在data中插值以便后期维护
          E_PIANO.forEach(function(group, gi) { // 循环 组
            group.forEach(function(key, ki) { // 循环 键
              // 插入组值
              key.groupId = gi;
              // 白键动态宽度
              if (ki == 1 || ki == 3 || ki == 6 || ki == 8 || ki == 10) { // 黑键专区
                key.type = 'B';
                key.area = this.KeyWidth;
                // 键位偏移量
                if (ki == 10) {
                  key.offset = this.KeyWidth * 1.5;
                } else if (ki == 8) {
                  key.offset = this.KeyWidth * 3.5;
                } else if (ki == 6) {
                  key.offset = this.KeyWidth * 5.5;
                } else if (ki == 3) {
                  key.offset = this.KeyWidth * 8.5;
                } else if (ki == 1) {
                  if (gi == 0) {
                    key.offset = this.KeyWidth * 1.5;
                  } else {
                    key.offset = this.KeyWidth * 10.5;
                  }
                }
              } else { // 白键专区
                key.type = 'W';
                if (ki == 11) {
                  key.groupEnd = true;
                }
                // 键宽与文字位置
                if (gi == 8) {
                  key.txtOS = this.KeyWidth;
                  key.area = this.KeyWidth;
                } else {
                  if (ki == 2 || ki == 7 || ki == 9) {
                    key.area = this.KeyWidth * 2;
                    key.txtOS = this.KeyWidth * 2;
                  } else {
                    key.area = this.KeyWidth * 1.5;
                    if (ki == 0 || ki == 5) {
                      key.txtOS = this.KeyWidth * 1.5 * 1.2;
                    } else if (ki == 4 || ki == 11) {
                      key.txtOS = this.KeyWidth * 1.5 * 0.6;
                    }
                  }
                  // 特殊赋值
                  if (gi == 0) {
                    key.area = this.KeyWidth * 1.5;
                    if (ki == 2) {
                      key.txtOS = this.KeyWidth * 1.5 * 0.6;
                    }
                  }
                }
              }
            }.bind(this));
            this.E_KEY = this.E_KEY.concat(group); // 创建E_KEY表
          }.bind(this));
          this.$forceUpdate();
        },
        ChartUpdate(e) {
          var CHART = [...this.E_KEY].reverse();
          // 三改: 数组重构，防止出现野生指针问题
          var groups = [];
          for (var i = 0; i < this.movement.long; i++) {
            var step = []
            for (var j = 0; j < this.movement.step; j++) {
              var keyBoard = [];
              CHART.forEach((e, k) => {
                var newObj = {};
                newObj.stepTime = i * 4 + j + 1;
                newObj.groupId = CHART[k].groupId;
                newObj.isPlay = false; // 插入默认状态
                newObj.scale = CHART[k].scale;
                newObj.type = CHART[k].type;
                newObj.key = CHART[k].key;
                keyBoard.push(newObj);
              });
              step.push(keyBoard);
            }
            groups = groups.concat(step);
          }
          this.Chart = groups;

          if (!e) {
            this.movement.staff = [];
            // 创建空表 将来可能会废弃
            groups.forEach(function(item, index) {
              this.movement.staff.push(['-']);
            }.bind(this))
          }
          this.$forceUpdate();
        },
        saveProject() {
          window.fileSaver(this.movement, this.projectName)
        },
        readProject() {
          window.fileLoader();
        },
        updateMIDI(MIDI) { // MIDI乐谱渲染主控器
          this.movement = {...MIDI};
          this.ChartUpdate(1);
          this.movement.staff.forEach(function(item, index) {
            if (item[0] != '-') { // 先过滤掉空
              item.forEach(function(midi, mid) { // staff深入一维
                this.Chart.forEach(function(group, gid) { // 解析Chart
                  group.forEach(function(key, kid) { // Chart深入一维
                    if (index == gid && midi[0] == key.key && midi[1] == key.groupId) {
                      key.isPlay = true;
                      key.actStyle = this.actStyle
                    }
                  }.bind(this))
                }.bind(this))
              }.bind(this))
            }
          }.bind(this));
          setTimeout(function() {
            vm.$forceUpdate()
          })
        },
        debugger(data) {}
      },
    })

    var isClick = false;
    // 按键判定前置
    $(window).mousedown(function() {
      isClick = true;
    });
    $(window).mouseup(function() {
      isClick = false;
      cleanAct();
    });
    $(".piano-key").mouseout(function() {
      cleanAct();
    });
    // 按键判定
    $(".piano-key").mouseover(function() {
      if (isClick) {
        createAudio($(this).attr('scale'));
      }
    });

    var NavView;
    // 页面加载播放
    window.onload = function() {
      if (/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) {
        // console.log("Wap");
        NavView = "wap";
        // "..."为spread运算符，ES6语法
        [...document.querySelectorAll('.piano-key')].forEach(function(item) {
          item.addEventListener('touchstart', function() {
            createAudio($(this).attr('scale'));
          });
        });
      } else {
        // console.log("Pc");
        NavView = "pc";
        $(".piano-key").mousedown(function() {
          createAudio($(this).attr('scale'));
        });
      }

      //去掉默认的contextmenu事件，否则会和右键事件同时出现。
      // document.oncontextmenu = function(e) {
      //   e.preventDefault();
      // };
    }
    var KeyboardVol = 0.3;
  </script>
</body>

</html>